﻿    using System;
    using System.Collections.Generic;
    using System.Reflection;
#if WinRT
    using Windows.UI.Xaml;
#else
    using System.Windows;
#endif



namespace DailyFx.UI
{
    /// <summary>
    ///		The context used during the execution of an Action or its guard.
    /// </summary>
    public class WeakAction : IDisposable
    {
		///<summary>
		///		Uses the action pipeline to invoke the method.
		///</summary>
		public static void Invoke ( object target, string method, DependencyObject view = null,
									FrameworkElement source = null,
									object eventArgs = null, object[] parameters = null )
		{
			var action = new WeakAction
			{
				Target		= target,
#if WinRT
                Method		= target.GetType().GetRuntimeMethods().Single( m => m.Name == method ),
#else
				Method		= target.GetType().GetMethod(method),
#endif
				MessageAction = new MessageAction { Method = method },

				View		= view,
				
				Source		= source,

				EventArgs	= eventArgs
			};

			if (parameters != null)
			{
				parameters.Apply(x => action.MessageAction
											.Parameters
											.Add(x as Parameter ?? new Parameter { Value = x })
								);
			}

			MessageAction.InvokeAction( action );
		}


		/// <summary>
		///		the target of the action apply on .
		/// </summary>
		WeakReference _target;

		/// <summary>
		///		The actual method info to be invoked.
		/// </summary>
		public MethodInfo Method;

		/// <summary>
		///		the reference of message action trigger of the action .
		/// </summary>
		private WeakReference _messageAction;

		/// <summary>
		///		the arguments' list for the action .
		/// </summary>
		private Dictionary<string, object> _args;

		/// <summary>
		///		the view of the target resident .
		/// </summary>
		private WeakReference _view;


		/// <summary>
		///		the source of the action fired .
		/// </summary>
		private WeakReference _source;

		/// <summary>
		///		Any event arguments associated with the action's invocation.
		/// </summary>
		public object EventArgs;


        /// <summary>
        ///		Determines whether the action can execute.
        /// </summary>
        public Func<bool> CanExecute ;

      
		/// <summary>
        ///		The instance on which the action is invoked.
        /// </summary>
        public object Target
        {
            get { return _target == null ? null : _target.Target; }
            set { _target = new WeakReference(value); }
        }

		/// <summary>
		///		The message being executed.
		/// </summary>
		public MessageAction MessageAction
		{
			get { return _messageAction == null ? null : _messageAction.Target as MessageAction; }
			set { _messageAction = new WeakReference(value); }
		}

		/// <summary>
		///		The view associated with the target.
		/// </summary>
		public DependencyObject View
		{
			get { return _view == null ? null : _view.Target as DependencyObject; }
			set { _view = new WeakReference(value); }
		}
       

        /// <summary>
        ///		The source from which the action fired .
        /// </summary>
        public FrameworkElement Source
        {
            get { return _source == null ? null : _source.Target as FrameworkElement; }
            set { _source = new WeakReference(value); }
        }

  
        /// <summary>
        ///		Gets or sets additional data needed to invoke the action.
        /// </summary>
        public object this [ string key ]
        {
            get
            {
                if ( this._args == null )
                    this._args = new Dictionary<string, object> ();

                object result;
                this._args.TryGetValue( key, out result );

                return result;
            }
            set
            {
                if ( this._args == null )
					this._args = new Dictionary<string, object> ();

                this._args[key] = value;
            }
        }

        /// <summary>
        ///		Performs application-defined tasks associated 
		///		 with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose ()
        {
            this.Disposing ( this, System.EventArgs.Empty );
        }

        /// <summary>
        /// Called when the execution context is disposed
        /// </summary>
        public event EventHandler Disposing = delegate { };
    }


}